package cn.tedu.model;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 一、单例设计：
 * 通过一种设计能够保证类的实例在内存只有一份。
 * 二、常用设计方法
 * 1.从类自身维度设计
 * 1)构造方法私有化
 * 2)在类的内部构件对象，并提供一个静态方法返回实例
 * 2.从外部维度设计(例如spring ioc 容器)
 * 三、自身设计维度的单例
 * 1.饿汉式(类加载时创建对象实例，无论外界是否需要都创建)
 * 2.懒汉式(延迟创建对象实例,需要对象实例时创建)
 */
class Singleton01{
    private static Singleton01 instance=new Singleton01();
    /**构造方法私有化*/
    private Singleton01(){}
    public static Singleton01 getInstance() {
        return instance;
    }
}
/**线程不安全的懒汉式单例*/
class Singleton02{
    private static Singleton02 instance;
    private Singleton02(){
        System.out.println("Singleton02()");
    }
    /**
     * 调用方法创建对象实例，并不是类加载时创建实例。
     * @return
     */
    public static Singleton02 getInstance() {
        if(instance==null){
            //Thread.yield();
            instance=new Singleton02();
        }
        return instance;
    }
}

/**线程安全的懒汉式单例*/
class Singleton03{
    /**
     * volatile 用于
     * 1.禁止指令重排序
     * 2.保证线程可见性(一个线程修改了变量的值，其它线程立刻可见)
     */
    private static volatile Singleton03 instance;
    private Singleton03(){
        System.out.println("Singleton03()");
    }
    /**
     * 双重校验锁设计
     * 既要保证线程安全，又要保证性能。
     */
    public static Singleton03 getInstance() {//100个线程并发访问
        if(instance==null) {//第一次检查：减少竞争
            synchronized (Singleton03.class) {
                if (instance == null) {//第二次检查：保证对象只创建一次
                    //Thread.yield();
                    instance = new Singleton03();
                    //1.为对象分配空间
                    //2.初始化属性
                    //3.调用构造方法
                    //4.把对象地址赋值给instance
                }
            }
        }
       return instance;
    }
}
/**枚举类型的恶汉式单例*/
enum Singleton04{
    INSTANCE;
}

class Singleton05{
    public Singleton05(){
        System.out.println("Singleton05()");
    }
    /**
     * 基于ThreadLocal实现线程内部单例，一个线程内部，key相同的实例只有一份
     * ThreadLocal提供了这样的一种机制，
     * 能够将某个对象绑定到当前线程，
     * 也能够从当前线程获取对象。
     */
    private static ThreadLocal<Singleton05> td=new ThreadLocal();
    public static Singleton05 getInstance(){
        //1.从当前线程获取实例
        Singleton05 instance=td.get();
        //2.当前线程没有，则创建，并存储到线程中(每个线程内部有一个map对象)
        if(instance==null){
            instance=new Singleton05();
            td.set(instance);//map中的key为this，指向的是threadlocal对象
        }
        return instance;
    }
    public static  void remove(){
        td.remove();//防止内存泄漏，线程不用这个对象了，可以考虑将其移除。
    }
}
public class SingletonTests {
    static class Task implements Runnable{
        @Override
        public void run() {
            Singleton05.getInstance();
            Singleton05.getInstance();
            Singleton05.getInstance();
            //Singleton05.remove();
        }
    }
    public static void main(String[] args) {
        Task task=new Task();
        Thread t1=new Thread(task);
        Thread t2=new Thread(task);
        Thread t3=new Thread(task);
        Thread t4=new Thread(task);
        Thread t5=new Thread(task);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}
